package com.vainycos.lotterysearch.service.mail;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.List;
import java.util.Objects;

/**
 * @author: Vainycos
 * @description 邮件发送器实现类
 */
@EnableAsync
@Slf4j
@AllArgsConstructor
public class JavaMailTemplate implements MailTemplate {

    private final JavaMailSender mailSender;

    private final MailProperties mailProperties;

    private static final String DEFAULT_ENCODING = "UTF-8";

    /**
     * 发送简单邮件
     *
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param toWho   收件人
     */
    @Override
    public void sendSimpleMessage(String subject, String content, List<String> toWho) {
        sendSimpleMessage(subject,
                content,
                toWho,
                null,
                null,
                null
        );
    }

    /**
     * 发送简单邮件
     *
     * @param subject    邮件主题
     * @param content    邮件内容
     * @param toWho      收件人
     * @param ccPeoples  抄送人
     * @param bccPeoples 密抄送人
     * @param nickname   发送人昵称
     */
    @Override
    public void sendSimpleMessage(String subject, String content, List<String> toWho, List<String> ccPeoples, List<String> bccPeoples, String nickname) {
        //创建一个发送简单文本邮件对象
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        JavaMailSupport mailSupport = JavaMailSupport.builder().build();
        //设置邮件的基本信息
        mailSupport.handleBasicInfo(simpleMailMessage, subject, content, toWho.stream().toArray(String[]::new), ccPeoples, bccPeoples, getFrom(nickname));
        mailSender.send(simpleMailMessage);
    }

    /**
     * 发送html内容邮件
     *
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param toWho   收件人
     */
    @Override
    public void sendHtmlMessage(String subject, String content, List<String> toWho) {
        sendHtmlMessage(subject,
                content,
                toWho,
                null,
                null
        );
    }

    /**
     * 发送html内容邮件
     *
     * @param subject    邮件主题
     * @param content    邮件内容
     * @param toWho      收件人
     * @param ccPeoples  抄送人
     * @param bccPeoples 密抄送人
     */
    @Override
    public void sendHtmlMessage(String subject, String content, List<String> toWho, List<String> ccPeoples, List<String> bccPeoples) {
        sendMimeMessage(subject,
                content,
                toWho,
                ccPeoples,
                bccPeoples,
                null,
                true,
                null
        );
    }

    /**
     * @param subject     邮件主题
     * @param content     邮件内容
     * @param toWho       收件人
     * @param attachments 文件地址
     * @param isHtml      邮件内容是否需要支持html
     */
    @Override
    public void sendMimeMessage(String subject, String content, List<String> toWho, List<String> attachments, boolean isHtml) {
        sendMimeMessage(subject,
                content,
                toWho,
                null,
                null,
                attachments,
                isHtml,
                null
        );
    }

    /**
     * 发送附件复杂邮件
     *
     * @param subject     邮件主题
     * @param content     邮件内容
     * @param toWho       收件人
     * @param ccPeoples   抄送人
     * @param bccPeoples  密抄送人
     * @param attachments 文件地址
     * @param isHtml      邮件内容是否需要支持html
     * @param nickname    发送人昵称
     */
    @Override
    public void sendMimeMessage(String subject, String content, List<String> toWho, List<String> ccPeoples, List<String> bccPeoples, List<String> attachments, boolean isHtml, String nickname) {
        checkParams(subject, content, toWho);
        customSendMessage(subject, content, toWho, ccPeoples, bccPeoples, attachments, isHtml, nickname);
    }

    /**
     * 发送附件复杂邮件
     *
     * @param subject     邮件主题
     * @param content     邮件内容
     * @param toWho       收件人
     * @param ccPeoples   抄送人
     * @param attachments 文件地址
     * @param isHtml      邮件内容是否需要支持html
     * @param nickname    发送人昵称
     */
    @Override
    public void sendMimeMessage(String subject, String content, List<String> toWho, List<String> ccPeoples, List<File> attachments, boolean isHtml, String nickname) {
        // 检验参数：邮件主题、收件人、邮件内容必须不为空才能够保证基本的逻辑执行
        checkParams(subject, content, toWho);
        customSendMessage(subject, content, toWho, ccPeoples, null, attachments, isHtml, nickname);
    }

    @Async
    @Override
    public void sendAsyncMessage(Mail mail) {
        if (mail == null){
            return;
        }
        // 检验参数：邮件主题、收件人、邮件内容必须不为空才能够保证基本的逻辑执行
        checkParams(mail.getSubject(), mail.getContent(), mail.getToWho());
        sendMimeMessage(mail.getSubject(), mail.getContent(), mail.getToWho(), mail.getCcPeoples(), mail.getAttachments(), mail.isHtml(), mail.getNickname());
    }

    @Async
    @Override
    public void sendAsyncMessage(Mail mail, MailCallBack callback) {
        // 邮件发送
        sendAsyncMessage(mail);
        // 回调函数
        callback.callBack(mail);
    }

    /**
     * 获取发件地址
     *
     * @param nickname 昵称
     * @return 发件地址
     */
    private String getFrom(String nickname) {
        String fromByte = "";
        try {
            if (StringUtils.isBlank(nickname)) {
                fromByte = mailProperties.getUsername();
            } else {
                fromByte = new String((nickname + " <" + mailProperties.getUsername() + ">").getBytes(DEFAULT_ENCODING));
            }
        } catch (Exception e) {
            log.error("初始化发件地址出错", e);
        }
        return fromByte;
    }

    private void checkParams(String subject, String content, List<String> toWho) {
        // 检验参数：邮件主题、收件人、邮件内容必须不为空才能够保证基本的逻辑执行
        if (subject == null || content == null || toWho == null || toWho.size() == 0) {
            log.error("邮件-> {} 无法继续执行，因为缺少基本的参数：邮件主题、邮件内容、收件人", subject);
            throw new RuntimeException("模板邮件无法继续发送，因为缺少必要的参数！");
        }
    }

    /**
     * 发送邮件-附件
     * @param subject     邮件主题
     * @param content     邮件内容
     * @param toWho       收件人
     * @param ccPeoples   抄送人
     * @param bccPeoples  密抄送人
     * @param attachments 文件地址
     * @param isHtml      邮件内容是否需要支持html
     * @param nickname    发送人昵称
     */
    private void customSendMessage(String subject, String content, List<String> toWho, List<String> ccPeoples, List<String> bccPeoples, List<? extends Object> attachments, boolean isHtml, String nickname) {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        JavaMailSupport mailSupport = JavaMailSupport.builder().build();
        MimeMessageHelper helper;
        try {
            helper = new MimeMessageHelper(mimeMessage, true, DEFAULT_ENCODING);

            if (Objects.nonNull(attachments) && attachments.size() > 0){
                Class<?> typeClass = attachments.get(0).getClass();
                String name = typeClass.getName();
                String typeName = name.substring(name.lastIndexOf('.'));
                if (typeName.endsWith(".String")) {
                    // 设置邮件的基本信息：这些函数都会在后面列出来
                    mailSupport.handleBasicInfo(helper, subject, content, toWho.stream().toArray(String[]::new), ccPeoples, bccPeoples, isHtml, getFrom(nickname));
                    // 处理附件
                    mailSupport.handleAttachment(helper, subject, (List<String>) attachments);
                }else if (typeName.endsWith(".File")) {
                    // 设置邮件的基本信息：这些函数都会在后面列出来
                    mailSupport.handleBasicInfo(helper, subject, content, toWho.stream().toArray(String[]::new), ccPeoples, null, isHtml, getFrom(nickname));
                    // 处理附件
                    mailSupport.handleFileAttachment(helper, subject, (List<File>) attachments);
                }
            }else {
                mailSupport.handleBasicInfo(helper, subject, content, toWho.stream().toArray(String[]::new), ccPeoples, bccPeoples, isHtml, getFrom(nickname));
            }

            // 发送该邮件
            mailSender.send(mimeMessage);
            return;
        } catch (MessagingException e) {
            log.error("邮件发送失败: 主题->" + subject, e);
        }
    }
}
